package com.xian.minespring.aop;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy;
import net.bytebuddy.implementation.InvocationHandlerAdapter;
import net.bytebuddy.matcher.ElementMatchers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * @author zhan
 * @version 2024/1/4
 */
public class ProxyResolver {
    final Logger logger = LoggerFactory.getLogger(getClass());

    ByteBuddy byteBuddy = new ByteBuddy();

    private static volatile ProxyResolver INSTANCE = null;

    public static ProxyResolver getInstance() {
        if (INSTANCE == null) {
            synchronized (ProxyResolver.class) {
                if (INSTANCE == null)
                    INSTANCE = new ProxyResolver();
            }
        }
        return INSTANCE;
    }

    private ProxyResolver() {
    }


    @SuppressWarnings("unchecked")
    public <T> T createProxy(T bean, InvocationHandler invocationHandler) {
        Class<?> targetClass = bean.getClass();
        logger.atDebug().log("create proxy for bean {} @{}", targetClass.getName(), Integer.toHexString(bean.hashCode()));
        Class<?> proxyClass = this.byteBuddy
                .subclass(targetClass, ConstructorStrategy.Default.DEFAULT_CONSTRUCTOR)
                .method(ElementMatchers.isPublic())
                .intercept(InvocationHandlerAdapter.of(new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        return invocationHandler.invoke(bean, method, args);
                    }
                }))
                .make()
                .load(targetClass.getClassLoader()).getLoaded();

        Object proxy = null;

        try {
            proxy = proxyClass.getConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return (T) proxy;

    }

}
